package video

import (
	"common/mildware"
	"common/models"
	"common/ofile"
	"common/snowflake"
	"common/validate"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	"math/rand"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
	"video/pkg/dao/redis"
)

const (
	VideoMP4 = "mp4"
)

// UpVideo 上传视频
// @Summary 上传视频
// @Description 上传视频 token(uid)->保存文件->mysql->redis
// @Tags 视频
// @Accept multipart/form-data
// @Param video formData file true "上传value=“video”"
// @Param object body docModel.DocUpVideoInfoReq false "参数"
// @Produce application/json
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} docModel.DocResp
// @Router /video/up [post]
func (h VHandler) UpVideo(c *gin.Context) {
	var (
		size, src, format, uid, nickName, authorId string
		err                                        error
	)
	resp := new(models.RespData)
	req := new(models.UpVideoInfoReq)
	if err := c.ShouldBind(req); err != nil {
		errs, ok := err.(validator.ValidationErrors)
		if !ok {
			zap.L().Error("Video:SearchLikeByName with invalid fail", zap.Error(err))
			resp.SendServerBusy(c)
			return
		} else {
			zap.L().Error("Video:SearchLikeByName with invalid fail", zap.Error(errs))
			resp.SendCodeWithMsg(c, models.CodeInvalidParam, validate.RemoveTopStruct(errs.Translate(validate.Trans)))
			return
		}
	}
	videResp := new(models.UpVideResp)
	//获得uid
	authorId, uid, nickName, err = mildware.GetCyrrentUserID(c)
	if err != nil {
		resp.SendCode(c, models.CodeInvalidToken)
		return
	}
	file, err := c.FormFile("video")
	if err != nil {
		zap.L().Info("Video:UpVideo video up err")
		resp.SendCode(c, models.CodeVideoUpErr)
		return
	}
	var upLoadDir string
	//定义文件保存地址 -uid
	upLoadDir = ofile.MkdirUserInfo(uid, ofile.Video)
	_, err = os.Stat(upLoadDir)
	if os.IsNotExist(err) {
		os.Mkdir(upLoadDir, os.ModePerm)
	}
	//判断视频类型 - mp4
	fileName := file.Filename
	format = strings.Split(fileName, ".")[1]
	if format != VideoMP4 {
		resp.SendCode(c, models.CodeVideoFormatErr)
		return
	}
	//fileName 脱敏
	fileId := strconv.FormatInt(time.Now().Unix(), 10) + strconv.Itoa(rand.Intn(999999-100000)+10000)
	newFileName := fileId + path.Ext(file.Filename)
	src = upLoadDir + newFileName
	err = c.SaveUploadedFile(file, src)
	if err != nil {
		zap.L().Error("Video : c.SaveUploadedFile error", zap.Error(err))
		resp.SendCode(c, models.CodeFileErr)
		return
	}
	//存储到数据库
	videoInfo := &models.VideoInfo{
		VideoId:               strconv.FormatInt(snowflake.GenID(), 10),
		Name:                  req.VideoName,
		AuthorId:              authorId, //Id
		Src:                   src,
		Size:                  size,
		Format:                format,
		AuthorNickName:        nickName,
		SimpleContext:         req.VideoSimpleInfo,
		TypeIds:               req.VideoTypeID,
		LikePeopleCount:       "0",
		DisLikePeopleCount:    "0",
		CollectionPeopleCount: "0",
	}
	//mysql
	if err = h.M.VideoInfoAdd(videoInfo); err != nil {
		zap.L().Error("Video :h.M.VideoInfoAdd error", zap.Error(err))
		resp.SendServerBusy(c)
		return
	}
	//将链接放到redis
	//video path:= video_id -> src
	if err = h.R.SetString(redis.VideoPath+videoInfo.VideoId, videoInfo.Src, 5*time.Minute); err != nil {
		zap.L().Error("Video :h.R.SetString error", zap.Error(err))
		resp.SendServerBusy(c)
		return
	}
	//vide id : video_id -> user ID
	if err = h.R.SetString(redis.VideoId+videoInfo.VideoId, videoInfo.AuthorId, 5*time.Minute); err != nil {
		zap.L().Error("Video :h.R.SetString error", zap.Error(err))
		resp.SendServerBusy(c)
		return
	}
	videResp.VideId = videoInfo.VideoId
	videResp.Src = videoInfo.Src
	resp.Data = videResp
	resp.SendSuccess(c)
}

// DownVideo 下载视频文件
// @Summary 下载视频文件
// @Description 下载视频文件
// @Tags 视频
// @Param video_id query string true "?video_id=xxx"
// @Success 200 {object}  interface{}
// @Router /video/down [get]
func (h VHandler) DownVideo(c *gin.Context) {
	resp := new(models.RespData)
	videoId := c.Query("video_id")
	//直接redis读
	result, err := h.R.GetString(redis.VideoPath + videoId)
	if err != nil {
		if errors.Is(err, redis.NoKey) {
			//获得地址
			//判断是否存在
			exist, Id, err := h.M.VideoCheckByUid(videoId)
			if err != nil {
				zap.L().Error("Video : h.M.VideoCheckByUid error", zap.Error(err))
				resp.SendServerBusy(c)
				return
			}
			if !exist {
				resp.SendCode(c, models.CodeNotFindFile)
				return
			}
			idStr := strconv.Itoa(Id)
			//查找视频
			video, err := h.M.VideoInfoQueryById(idStr)
			if err != nil {
				zap.L().Error("Video : h.M.VideoInfoQueryById error", zap.Error(err))
				resp.SendServerBusy(c)
				return
			}
			//将链接放到redis
			if err = h.R.SetString(redis.VideoPath+video.VideoId, video.Src, 5*time.Minute); err != nil {
				zap.L().Error("Video :h.R.SetString error", zap.Error(err))
				resp.SendServerBusy(c)
				return
			}
			//将视频的点赞 - 不喜欢 -收藏信息 存放到redis
			infoStr := strings.Join([]string{video.LikePeopleCount, video.DisLikePeopleCount, video.CollectionPeopleCount}, models.SplitFormat)
			if err = h.R.SetString(redis.VideoInfoLikeOrNo+video.VideoId, infoStr, 5*time.Minute); err != nil {
				zap.L().Error("Video :h.R.SetString error", zap.Error(err))
				resp.SendServerBusy(c)
				return
			}
			//响应一个文件
			c.File(video.Src)
			return
		}
		zap.L().Error("Video : h.R.GetString error", zap.Error(err))
	}
	if result != "" {
		c.File(result)
		return
	}
}
